package utility

import (
	"context"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/base64"
	"encoding/json"
	"github.com/gogf/gf/v2/crypto/gmd5"
	"github.com/gogf/gf/v2/frame/g"
	"math/rand"
	"strconv"
	"strings"
	"time"
	"github.com/google/uuid"
)


var TimeNum int

var Sub string

var Key string

var Header = map[string]interface{}{
	"alg": "HS256",
	"typ": "JWT",
}


func GetToken (payload map[string]interface{}) (token string) {
	nowTime := time.Now().Unix()
	payload["iss"] = "im_http"
	payload["iat"] = nowTime

	s, ok := payload["iat"].(int)

	if !ok {
		//TODO
		return
	}

	payload["exp"] = s + TimeNum * 60
	payload["nbf"] = nowTime
	payload["sub"] = Sub

	id := uuid.New()

	// 设置随机数
	rand.Seed(time.Now().UnixNano())

	// 生成 1 到 100000 之间的随机数
	randomNumber := rand.Intn(100000) + 1
	randomString := strconv.Itoa(randomNumber)
	// 添加前缀
	prefixedID := "JWT" + id.String() + randomString

	encrypt, err := gmd5.Encrypt(prefixedID)

	if err != nil {
		//TODO
		return
	}

	payload["jti"] = encrypt

	marshal, err := json.Marshal(Header)
	if err != nil {
		//TODO
		return
	}

	base64Header := base64UrlEncode(string(marshal))

	bytes, err := json.Marshal(payload)

	if err != nil {
		//TODO
		return
	}

	base64payload := base64UrlEncode(string(bytes))


	param := base64Header + "." + base64payload
	sign := signature(param, Key, Header["alg"].(string))
	if sign == "" {
		return
	}

	token = base64Header + "." + base64payload + "." + sign

	return
}





// JwtVerifyToken 验证 JWT Token 是否有效
func VerifyToken(token string) (payload map[string]interface{}) {
	key := "12345678"

	tokens := strings.Split(token, ".")
	if len(tokens) != 3 {
		return nil
	}

	//头，参数，签名
	base64Header, base64Payload, sign := tokens[0], tokens[1], tokens[2]

	headerJSON, err := base64UrlDecode(base64Header)
	if err != nil {
		g.Log().Error(context.TODO(), "base64UrlDecode错误", err)
		return nil
	}

	header := make(map[string]string)
	if err := json.Unmarshal(headerJSON, &header); err != nil {
		g.Log().Error(context.TODO(), "json.Unmarshal错误", err)
		return nil
	}

	if signature(base64Header+"."+base64Payload, key, header["alg"]) != sign {
		return nil
	}

	payloadJSON, err := base64UrlDecode(base64Payload)
	if err != nil {
		g.Log().Error(context.TODO(), "base64UrlDecode", err)
		return nil
	}

	payload = make(map[string]interface{})
	if err := json.Unmarshal(payloadJSON, &payload); err != nil {
		g.Log().Error(context.TODO(), "json.Unmarshal", err)
		return nil
	}

	if iat, ok := payload["iat"].(float64); ok && int64(iat) > time.Now().Unix() {
		g.Log().Error(context.TODO(), "token验证失败")
		return nil
	}

	if nbf, ok := payload["nbf"].(float64); ok && int64(nbf) > time.Now().Unix() {
		g.Log().Error(context.TODO(), "token验证失败")
		return nil
	}

	return payload
}

func base64UrlEncode(input string) string {
	encoded := base64.URLEncoding.EncodeToString([]byte(input))
	return strings.TrimRight(encoded, "=")
}

func base64UrlDecode(input string) ([]byte, error) {
	padding := len(input) % 4
	if padding > 0 {
		input += strings.Repeat("=", 4-padding)
	}
	return base64.URLEncoding.DecodeString(input)
}

func signature(input string, key string, alg string) string {
	if alg == "HS256" || alg == ""{
		h := hmac.New(sha256.New, []byte(key))
		h.Write([]byte(input))
		return base64UrlEncode(string(h.Sum(nil)))
	}
	return ""
}
